/*对axios进行简单的二次封装
对于拦截器的封装。这里有三种：
1、全局拦截器：即调用axios.create()后，在构造函数中使用的拦截器（一般我们用这个就能解决大部分常用而不需要变化的的需求了）；
2、实例化拦截器：即在new Service(options)时，传入的拦截器。这里的拦截器是为了解决在不同的场景，拦截可能是不一样的；
3、对于单个请求的拦截器：即在每次请求数据时，传入的拦截器。这里的拦截器是为了解决个别特殊的接口请求，而进行特殊的拦截处理
*/
import axios from 'axios';
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
import { RequestInterceptors, RequestConfig } from './type/index';

class Service {
  // axios 实例
  instance: AxiosInstance;
  //拦截器对象。
  interceptorsObj?: RequestInterceptors<AxiosResponse>;
  constructor(config: RequestConfig) {
    this.instance = axios.create(config);
    this.interceptorsObj = config.interceptors;
    //关于全局拦截器和实例化拦截的优先级：实例化请求=>全局请求；全局响应=>实例化响应

    //全局拦截器的封装。这比较简单，直接取instance上的方法就行:
    //全局请求拦截
    this.instance.interceptors.request.use(
      (config: AxiosRequestConfig) => {
        console.log('全局请求拦截器');
        return config;
      },
      (err: AxiosError) => {
        console.log('全局请求拦截器错误');
        return Promise.reject(err);
      },
    );

    // 使用实例化拦截器
    //实例化请求
    this.instance.interceptors.request.use(
      this.interceptorsObj?.requestInterceptors,
      this.interceptorsObj?.requestInterceptorsCatch,
    );
    //实例化响应
    this.instance.interceptors.response.use(
      this.interceptorsObj?.responseInterceptors,
      this.interceptorsObj?.responseInterceptorsCatch,
    );

    //全局响应拦截（保证在最后）
    this.instance.interceptors.response.use(
      // 接口返回的数据都在res.data下，所以我们直接返回res.data
      (res: AxiosResponse) => {
        console.log('全局响应拦截器');
        return res.data;
      },
      (err: AxiosError) => {
        console.log('全局请求拦截器错误');
        return Promise.reject(err);
      },
    );
  }
  //这里的泛型是为了约束返回值
  request<T>(config: RequestConfig<T>): Promise<T> {
    return new Promise((resolve, reject) => {
      // 如果我们为单个请求设置拦截器，这里使用单个请求的拦截器
      if (config.interceptors?.requestInterceptors) {
        config = config.interceptors.requestInterceptors(config);
      }
      this.instance
        .request<unknown, T>(config)
        .then((res) => {
          // 如果我们为单个响应设置拦截器，这里使用单个响应的拦截器
          if (config.interceptors?.responseInterceptors) {
            res = config.interceptors.responseInterceptors(res);
          }
          resolve(res);
        })
        .catch((err: AxiosError) => {
          reject(err);
        });
    });
  }
}
export default Service;
